package com.moli.iov.admin.component;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSONObject;
import com.moli.iov.admin.service.IWebLogFacadeService;
import com.moli.iov.sys.constants.Constant;
import com.moli.iov.sys.model.po.User;
import com.moli.iov.sys.model.po.mongodb.WebLog;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * <p>
 * 统一日志处理
 * </p>
 *
 * @author zql
 * @since 2019/9/24 11:40
 */
@Slf4j
@Aspect
@Component
@Order(1)
public class WebLogAspect {

  @Autowired
  private IWebLogFacadeService webLogFacadeService;

  @Autowired
  private CacheManger cacheManger;

  /**
   * 排除方法 结果
   */
  private static final String[] API_EX = {"list", "get"};

  @Pointcut("execution(public * com.moli.iov.admin.web.controller.*.*(..))")
  public void webLog() {
  }

  @Around("webLog()")
  public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

    //获取当前请求对象
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();

    Date startTime = new Date();
    Object result = joinPoint.proceed();
    saveLog(request, joinPoint, result, startTime);
    return result;
  }

  /**
   * 保存日志
   * @param request
   * @param joinPoint
   * @param result
   * @param beginTime
   */
  private void saveLog(HttpServletRequest request, ProceedingJoinPoint joinPoint, Object result, Date beginTime){
    try {
      Signature signature = joinPoint.getSignature();
      MethodSignature methodSignature = (MethodSignature) signature;
      Method method = methodSignature.getMethod();

      WebLog webLog = new WebLog();

      Date endTime = new Date();
      String urlStr = request.getRequestURL().toString();
      webLog.setBasePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath()));
      webLog.setIp(request.getRemoteUser());
      webLog.setMethod(request.getMethod());
      webLog.setParam(getParameter(method, joinPoint.getArgs()));

      webLog.setSpendTime((int) (endTime.getTime() - beginTime.getTime()));
      webLog.setBeginTime(beginTime);
      webLog.setEndTime(endTime);
      webLog.setUrl(request.getRequestURL().toString());
      String uri = request.getRequestURI();
      webLog.setUri(uri);

      if(!uri.contains(API_EX[0]) && !uri.contains(API_EX[1])){
        webLog.setResult(JSONObject.toJSONString(result));
      }

      webLogFacadeService.saveLog(getSysUser(request, webLog));
    }catch(Exception e){
      log.info("保存日志异常", e);
    }
  }

  /**
   * 根据方法和传入的参数获取请求参数
   */
  private String getParameter(Method method, Object[] args) {
    List<Object> argList = new ArrayList<>();
    Parameter[] parameters = method.getParameters();
    for (int i = 0; i < parameters.length; i++) {
      //将RequestBody注解修饰的参数作为请求参数
      RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
      if (requestBody != null) {
        argList.add(args[i]);
      }
      //将RequestParam注解修饰的参数作为请求参数
      RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
      if (requestParam != null) {
        Map<String, Object> map = new HashMap<>();
        String key = parameters[i].getName();
        if (!StringUtils.isEmpty(requestParam.value())) {
          key = requestParam.value();
        }
        map.put(key, args[i]);
        argList.add(map);
      }
    }
    if (argList.size() == 0) {
      return null;
    } else if (argList.size() == 1) {
      return JSONObject.toJSONString(argList.get(0));
    } else {
      return JSONObject.toJSONString(argList);
    }
  }

  private WebLog getSysUser(HttpServletRequest request, WebLog webLog){
    String account = (String)request.getAttribute(Constant.DEFAULT_REQUEST_PERMISSION);
    try{
      User user = cacheManger.getUser(account);
      if(user == null){
        return webLog;
      }

      webLog.setUserId(user.getUserId());
      webLog.setRealName(user.getRealName());
      webLog.setUserType(user.getUserType());
      webLog.setCompanyId(user.getCompanyId());
      webLog.setCompanyName(user.getCompanyName());
    }catch(Exception e){
    }

    return webLog;
  }
}
